/*
 * Copyright 2000-2003 Virginia Commonwealth University
 * -----------------------------------------------------------------------------
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is furnished
 * to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 *
 *-----------------------------------------------------------------------------
 *
 *   AUTHORS:
 *
 *   Jeffrey Vincent Siebers
 *
*/
/*  General Utilities for CPP programs
      File Created:
            18-December-1995: Combined ok_check.cpp and some open_file
      Modification History:
            01-Feb-1996: JVS: filename used in open_file has extension only in openfile
            09-Feb-1996: JVS: Add eprintf: outputs to screen and a buffer called pbuffer
                                                pbuffer is a global whose memory must be allocated
                                                this is useful for creating a "history" file
      17-June-1996: JVS: change latex_string so will work with win95/bc5.0
                         cannot have for(int i=0,j=0; ). j will not increment.
      05-Sept-1996: JVS: Add allocate_pbuffer and print_runtime_info
      23-April-1997: JVS: Add interpolate
      06-Jan-1998: JVS: Add array_read
      11-June-1998: jvs: add eprintf and view_errors
      22-Sept-1998: JVS: fix memory leak in eprintf
      07-Dec-1998: JVS: Add clean_name
      18-Feb-1999: JVS: eliminate atof in array_read because of failures
      25-Feb-1999: JVS: array_read will now read numbers that start with .
      26-Feb-1999: JVS: Add array_read for strings
      02-March-1999: JVS: Add global eprint_mode so can quite eprintf statements
      24-March-1999: JVS: Modify clean_name so names cannot have *'s in them
      July 20, 1999: JVS: eprintf modified to use fprintf(stdout), rather than printf
      Dec 3, 1999: JVS: Add check_byte_order
      Jan 11, 2000: JVS: Modify clean_name so names cannot have / in them
      Jun 16, 2000: JVS: Change open_file so will read in .extension properly when a . is in
                         the path name
      April 25, 2001: JVS: Add cp(SourceFile,DestinationFile)
      May 29, 2001: JVS: clean_name now removes & as well
      May 31, 2002: add reverse_short_byte_order
      Feb 18, 2004: JVS: Add writeBigEndianBinaryFile()
      Feb 10, 2005: JVS: Add writeLittleEndianBinaryFile() and writeBinaryFile()
      Feb 11, 2005: JVS: Add reverse_int_byte_order
      April 21, 2005: JVS: Add readBinaryDataFromFile
*/
#ifdef MSVC
#include <iostream>  // so that namespace std becomes defined
#endif
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <cctype>
#include <ctime>

using namespace std;

#include "utilities.h"

/* ************************************************************************** */
int reverse_int_byte_order(int xold)
{
   int xnew;
   char *pn   = (char *) &xnew;
   char *po   = (char *) &xold;
   pn[0] = po[3];
   pn[1] = po[2];
   pn[2] = po[1];
   pn[3] = po[0];
   return(xnew);
}
/* *************************************************************************** */
float reverse_float_byte_order(float xold)
{
   float xnew;
   char *pn   = (char *) &xnew;
   char *po   = (char *) &xold;
   pn[0] = po[3];
   pn[1] = po[2];
   pn[2] = po[1];
   pn[3] = po[0];
   return(xnew);
}
/* **************************************************************************** */
short reverse_short_byte_order(short xold)
{
   short xnew;
   char *pn   = (char *) &xnew;
   char *po   = (char *) &xold;
   pn[0] = po[1];
   pn[1] = po[0];
   return(xnew);
}
/* **************************************************************************** */
int check_byte_order()
{
  /* Determine the byte order on this machine */
  float ftest=1.0f; /* assign a float to 1.0 */
  char *pf = (char *) &ftest;
  // printf("\n \t %x %x %x %x", pf[0],pf[1],pf[2],pf[3]);
  if(pf[0] == 0 && pf[3] != 0)
  {
    // printf("\n\n Byte order: INTEL / ALPHA,LINUX -> LITLE_ENDIAN \n");
    return(LITTLE_ENDIAN);
  }else if(pf[0] != 0 && pf[3] == 0)
  {
    // printf("\n\n Byte order: OTHER (SGI,SUN-SOLARIS) -> BIG_ENDIAN \n ");
    return(BIG_ENDIAN);
  }
  else
  {
        printf("\n\n ERROR: indeterminate byte order");
        printf("\n \t %x %x %x %x", pf[0],pf[1],pf[2],pf[3]);
        return(UNKNOWN_ENDIAN);
  }
}
/* ************************************************** */
void print_runtime_info(int argc, char *argv[])
{  // print file header stuff
        printf("\n Command Line: ");
        for(int i=0; i<argc; i++) printf(" %s", argv[i]);
        // printf("\n Program %s Revision %f",  Prog_Name,Revision);
        printf("\n \t Copyright XXXX MCV");
        time_t t;
        t = time(NULL);
        printf("\n Run on %s\n",  ctime(&t) );
}
/* ****************************************************************** */
void allocate_pbuffer()
{
   pbuffer = (char *)malloc(MAX_BUFFER_SIZE * sizeof(char) +2);
      if(pbuffer == NULL)
      {
                  printf("\n Error Allocating Memory Buffer");
                  exit(EXIT_FAILURE);
   }
}
/* ***************************************************************** */
/* *********************************************************************** */
int advance(char *istr, int *sval, int len)
{                           /* advances past white-space in file */
      while( !isspace(istr[*sval]) && (*sval < len) )
            *sval+=1; /* advance to space */
      while( isspace(istr[*sval]) && (*sval < len) )
            *sval+=1; /* advance to next thing */
      if(*sval > len) return(FAIL); /* return 0 when fails */
      return (OK);
}
/* ********************************************************************** */
int my_isascii( int c )
{
   return( !(c < 0 || c > 0177) );
}
/* ********************************************************************* */
int clean_name(char *name)
{
   int len = strlen(name);
   char *tname = (char *) calloc(len+1, sizeof(char));
   if(tname == NULL)
   {
      eprintf("\n ERROR: memory allocation error");
      return(FAIL);
   }
   strcpy(tname, name);
   if(clean_name(tname, name)!= OK)
   {
      eprintf("\n ERROR: cleaning Name");
      return(FAIL);
   }
   free(tname);
   return(OK);
}
/* ********************************************************************* */
int clean_name(char *tmp_path, char *opath)
{
   /* remove spaces, *'s, :'s &'s and commas from the name */
   int len = strlen(tmp_path);
   int o_index=0;
   for(int i=0; i<len; i++)
   {
      if( isspace(tmp_path[i] ) )
      {
          if( o_index &&              // add a _ if not first char
              opath[o_index-1] != '_' ) // and if previous char not a _
         opath[o_index++] = '_';
      }
      else
      if( my_isascii( tmp_path[i] ) &&
          tmp_path[i] != '&'   &&
          tmp_path[i] != ','   &&
          tmp_path[i] != '*'   &&
          tmp_path[i] != '/'   &&
          tmp_path[i] != ':' )
          opath[o_index++] = tmp_path[i];
   }
   opath[o_index] = '\0'; /* terminate the string */

   return(OK);
}
/* *********************************************************************** */
FILE *open_file(char *filename, const char*extension, const char *access)
{
  char string[MAX_STR_LEN];
  FILE *strm = NULL;

  if(filename[0]=='\0')
   {
      printf("\n INPUT FILENAME (%s) > ",access);
      fgets(string,MAX_STR_LEN,stdin);
      sscanf(string,"%s",filename);
      printf(" FILE %s opened \n", filename);
   }
   int len=strlen(filename);

   if( len + strlen(extension) >= MAX_STR_LEN)
   {
      printf("\n ERROR: String Length  of %s.%s Exceeds Maximum",
              filename, extension);
      return(NULL);
   }

   // char *filename1 = new(char[len+strlen(extension)+1]);

   const int filenameLength = len+strlen(extension)+1;
   char *filename1 = new(char[filenameLength]);

   strcpy(filename1,filename); // temp filename for appending extension

   /* check if file name has .extension    */
   /* if it does not, add .extension to it */
   int i=len-1;
   while(i > 0 && filename[i--] != '.');
   //   printf("\n Comparing %s to %s", extension, filename+i+1);
   if(strcmp(extension, filename+i+1)  )
      strcat(filename1,extension);
   if( (strm = fopen(filename1, access) ) == NULL )
   {
      printf("\n ERROR OPENING FILE %s (mode %s)", filename1,access);
   }
   delete(filename1);
   return(strm);
}
/* *********************************************************************** */
int ok_check(void)                          /* GETS RESPONSE FROM USER      */
{                                           /* IF OK TO DO SOMETHING        */
   char reply[MAX_STR_LEN];                 /* RETURNS 1 ONLY IF REPLY Y    */
                                            /* OR y ELSE RETURNS 0          */
   fgets(reply,MAX_STR_LEN,stdin);
   if(  ( strncmp(reply,"Y",1)==0 )||
   ( strncmp(reply,"y",1)==0 ))
     return(1);
   return(0);
}
/* ***********************************************************************  */
int ok_checks(char *string)
{
   printf("\n %s", string);
   return(ok_check());
}
/* ********************************************************************** */
#include <stdarg.h> // for va function
int pprintf(char *fmt, ... )
{
  va_list  argptr;         /* Argument list pointer   */
  char str[MAX_STR_LEN];           /* Buffer to build sting into   */
  int cnt;            /* Result of SPRINTF for return */
  va_start( argptr, fmt );      /* Initialize va_ functions   */
  cnt = vsprintf( str, fmt, argptr );   /* prints string to buffer   */
  if(str[0] == '\0') return(0);
  printf("%s", str);   /* Send  to screen */
  if(pbuffer != NULL && strlen(pbuffer) + strlen(str) < MAX_BUFFER_SIZE)
     strcat(pbuffer,str);
  else
     printf("\n ERROR: pbuffer is full");
  va_end( argptr );         /* Close va_ functions      */
  return( cnt );         /* Return the conversion count   */
}
/* *********************************************************************** */
/* eprintf: for buffering error reports, writes error messages to a buffer,
   and, also can echo them to the screen (if set at compile time)
   at first instance, allocates memory for the error buffer              */
static char *ebuffer = NULL;
int eprintf(const char *fmt, ... )
{
  va_list  argptr;         /* Argument list pointer   */
  char str[MAX_STR_LEN];           /* Buffer to build sting into   */
  int cnt;            /* Result of SPRINTF for return */
  va_start( argptr, fmt );      /* Initialize va_ functions   */
  cnt = vsprintf( str, fmt, argptr );   /* prints string to buffer   */
  if(str[0] == '\0') return(0);

  if(eprintf_mode==ON)
     fprintf(stdout,"%s", str);   /* Send  to screen */

  // allocate memory for the error message
  int ilen = 0;
  if(ebuffer != NULL)
  {
     ilen+=strlen(ebuffer);
     ebuffer = (char *) realloc(ebuffer, (ilen+strlen(str)+1)*sizeof(char));
  }
  else
     ebuffer = (char *) calloc(ilen+strlen(str)+1,sizeof(char));

  if(ebuffer == NULL)
  {
     printf("\n ERROR: ebuffer cannot be allocated in eprintf");
  }
  else
     strcat(ebuffer,str);
  va_end( argptr );         /* Close va_ functions      */
  return( cnt );         /* Return the conversion count   */
}
int view_errors(void)
{
   printf("\n%s\n",ebuffer);
   return(OK);
}
/* ************************************************************************** */
int latex_string(char *string, char *nstring)
{
  // adds \\ in front of % so % will show up in the comment when printed
  // with LaTeX
   // must change all %'s to \% for latex output
   // also, must do the same for $, &, # _  { and }
   int len = strlen(string);
   int sval=0;
   int j;
   while(isspace(string[sval]) )sval++; // remove space from start of string
   while(isspace(string[len-1]))len--; // remove space from end to string

   j=0;
   for(int i=sval;i<len;i++)
   {
      if(string[i]=='%' ||
         string[i]=='$' ||
         string[i]=='&' ||
         string[i]=='#' ||
         string[i]=='_' ||
         string[i]=='{' ||
         string[i]=='}' )
      {
         nstring[j++]='\\';
      }
      else
      if(string[i]=='<' ||
         string[i]=='>' )
      {
         nstring[j++]='$';
      }
      nstring[j++] = string[i];
      if(string[i]=='<' ||
      string[i]=='>' )
      {
         nstring[j++]='$';
      }
   }
   nstring[j]='\0';
/*   printf("\n string: %s", string);
   printf("\n nstring: %d %s",j, nstring); */
   return(OK);
}
/* ************************************************************************** */
float interpolate(float xh, float xl, float xm, float yh, float yl)
{
  return(yh - (xh-xm)/(xh-xl)*(yh-yl));
}
/* *********************************************************************** */
// #define DEBUG_ARRAY
/* ********************************************************************** */
int array_read(char *in_string, float *array, int max_array)
{
   char delimeter_string[MAX_STR_LEN];
   sprintf(delimeter_string," ,\t"); /* spaces, commas, and tabs */

   char *p; /* pointer to string read in */
   p = strtok(in_string,delimeter_string);
   int i=0;
   if(p!=NULL)
   {
      array[i++]=(float)atof(p); /* get the first value */
      // if( sscanf(p,"%f",&array[i]) == 1) i++; // sscanf rounds values....
      do{             /* get remaining values */
         p = strtok(NULL,delimeter_string);
         if(p!=NULL)
         {
         //array[i++] = atof(p);
            if( sscanf(p,"%f",&array[i]) == 1) i++;
            // printf("\n Got Value of %f", array[i-1]);
         }
      }while(p!=NULL && i < max_array);
   }

#ifdef DEBUG_ARRAY
   printf("\n atof %d", i);
   for(int j=0; j<i; j++) {
     //     array[j] = 0.0001*round(1000.0*array[j]);
      printf("\n i = %d, %f",j,array[j]);
   }
#endif
   return(i);

}
int array_read(FILE *istrm, float *array, int max_array)
{
   // reads in an array of floats from a single line of istrm
   // returns the number of elements read in

   char in_string[MAX_STR_LEN];

   if(fgets(in_string, MAX_STR_LEN, istrm) == NULL ) return(FAIL);
#ifdef DEBUG_ARRAY
   printf("\nInput String\n %s", in_string);
#endif

   int slen = strlen(in_string);

   int k=0;
   while(isspace(in_string[k]) && k < slen) k++;
   if(slen==0 || !(isdigit(in_string[k])
              ||    in_string[k] == '.'
              ||    in_string[k] == '+'
              ||    in_string[k] == '-'))
   {
      return(0); // skip blank and non-numerical lines
   }
   int nread = array_read(in_string,array,max_array);

   return(nread);  // return the number of elements read
}
/* ********************************************************************** */
int copy(char *SourceFile, char *DestinationFile)
{
  /* Copies sourceFile to destination file like unix cp command */
  FILE *sStream = fopen(SourceFile, "rb");
  if(sStream == NULL)
  {
     perror("\n ERROR: copy: ");
     printf("\n ERROR: copy: Opening Source File %s",SourceFile);return(FAIL);
  }
  FILE *dStream = fopen(DestinationFile,"wb");
  if(dStream == NULL)
  {
     perror("\n ERROR: copy:");
     printf("\n ERROR: copy: Opening Destination File %s",DestinationFile);return(FAIL);
  }
  char buffer[1000];
  int nRead;
  do{
     nRead = fread(buffer, sizeof(char), 1000, sStream);
     if( nRead )
        fwrite(buffer, sizeof(char), nRead, dStream);
  }while( !feof(sStream) && !ferror(dStream) && !ferror(sStream) );
  if(ferror(sStream) || ferror(dStream) )
  {
     perror("ERROR: Copy: ");
     printf("\n ERROR: source %s, destination %s", SourceFile, DestinationFile);
     return(FAIL);
  }
  fclose(sStream);
  fclose(dStream);
  return(OK);
}
/* ********************************************************************** */
/* ************************************************************************************ */
int readBinaryDataFromFile(FILE *iStream, int nItemsToRead, float **arrayToRead, int swab_flag)
{
  // Reads binary data to stream, swab's if requested (1=swab, 0=don't swab)
  // Swab if needed...Put swabbed results in different array so no need to "unswab" when done
  // Allocate memory to read array into
   float *inputArray;
   inputArray = (float *) calloc(nItemsToRead,sizeof(float));
   if(inputArray == NULL) {
      printf("\n ERROR: Allocating memory for inputArray in readBinaryDataFromFile");
      return(FAIL);
   }
   if(OK != readBinaryDataFromFile(iStream, nItemsToRead, inputArray, swab_flag)) {
     printf("\n ERROR: Reading binary data from file"); return(FAIL);
   }
   *arrayToRead = inputArray;
   return(OK);
}
/* ************************************************************************************ */
int readBinaryDataFromFile(FILE *iStream, int nItemsToRead, float *inputArray, int swab_flag)
{
  // Reads binary data to stream, swab's if requested (1=swab, 0=don't swab)
  // Swab if needed...Put swabbed results in different array so no need to "unswab" when done
  // Allocate memory to read array into
   // Read in the array....
   int nRead=fread(inputArray,sizeof(float),nItemsToRead, iStream);
   if(nRead != nItemsToRead) {
     eprintf("\n ERROR: Wrong number read from file (%d %d)\n",
           nRead, nItemsToRead); return(FAIL);
   }
   // Check if need to swab the data
   if(swab_flag) // swab if swab_flag != 0
   {
      for(int index=0; index<nItemsToRead;index++)
      {
         inputArray[index] = reverse_float_byte_order( inputArray[index] );
      }
   }
   return(OK);
}
/* ***************************************************************************************** */
int writeBinaryFile(char *binaryFileName, int nItemsToWrite, float *arrayToWrite, int swab_flag)
{
   FILE *outputStream= fopen(binaryFileName,"wb");
   if (outputStream == NULL) {
     eprintf("\n ERROR: Cannot open file %s for writing\n",binaryFileName); return(FAIL);
   }
   if(OK != writeBinaryDataToFile(outputStream, nItemsToWrite, arrayToWrite, swab_flag) )
   {
     eprintf("\n ERROR: Writing Binary File"); return(FAIL);
   }
   fclose(outputStream);
   return(OK);
}
/* ************************************************************************************ */
int writeBinaryDataToFile(FILE *outputStream, int nItemsToWrite, float *arrayToWrite, int swab_flag)
{
  // Writes binary data to stream, swab's if requested (1=swab, 0=don't swab)
   // Swab if needed...Put swabbed results in different array so no need to "unswab" when done
   float *swabbedArray;
   if(swab_flag) // swab if swab_flag != 0
   {
      //
      swabbedArray = (float *) calloc(nItemsToWrite,sizeof(float));
      if(swabbedArray == NULL) {
      eprintf("\n ERROR: Allocating memory for swabbedArray in writeBinaryFile");
        return(FAIL);
      }
      for(int index=0; index<nItemsToWrite;index++)
      {
         swabbedArray[index] = reverse_float_byte_order( arrayToWrite[index] );
      }
   } else {
     swabbedArray = arrayToWrite;
   }
   // Check that writing positive number of items
   if(nItemsToWrite < 0 )
   {
     eprintf("\n ERROR: writeBinaryDataToFile: nItemsToWrite= %d < 0", nItemsToWrite); return(FAIL);
   }
   // Write the dose distribution
   int nWrite=fwrite(swabbedArray,sizeof(float),nItemsToWrite, outputStream);
   if(nWrite != nItemsToWrite) {
     eprintf("\n ERROR: Wrong number written to file (%d %d)\n",
           nWrite, nItemsToWrite); return(FAIL);
   }
   // free swabbedArray if it was allocated here
   if(swab_flag) {
     free(swabbedArray);
   }
   return(OK);
}
/* ***************************************************************************************************** */

int writeBigEndianBinaryFile(char *binaryFileName,  int nItemsToWrite, float *arrayToWrite)
{
   // Pinnacle doses always written in BIG_ENDIAN format... Check if need to swab.....
   int swab_flag = 0;
   switch( (check_byte_order()) )
   {
      case BIG_ENDIAN:
         break;
      case LITTLE_ENDIAN:
         swab_flag=1;
        break;
      default:
         eprintf("\n ERROR: Indeterminate Byte Order\n");
         return(FAIL);
   }
   if(OK != writeBinaryFile(binaryFileName, nItemsToWrite, arrayToWrite, swab_flag) )
   {
     printf("\n ERROR: Writing dose file %s", binaryFileName); return(FAIL);
   }
   return(OK);
}
/* ***************************************************************************************************** */
int writeLittleEndianBinaryFile(char *binaryFileName,  int nItemsToWrite, float *arrayToWrite)
{
   // Pinnacle doses always written in BIG_ENDIAN format... Check if need to swab.....
   int swab_flag = 0;
   switch( (check_byte_order()) )
   {
      case BIG_ENDIAN:
      swab_flag=1;
         break;
      case LITTLE_ENDIAN:
        break;
      default:
         eprintf("\n ERROR: Indeterminate Byte Order\n");
         return(FAIL);
   }
   if(OK != writeBinaryFile(binaryFileName, nItemsToWrite, arrayToWrite, swab_flag) )
   {
     printf("\n ERROR: Writing dose file %s", binaryFileName); return(FAIL);
   }
   return(OK);
}
/* ***************************************************************************************************** */
char *strnset(char *s, int ch, size_t n)
{  /* mimic strnset command in dos/ os2/ win / ... */
   for(int i=0; i< (int) n; i++)
   {
     if(s[i] == STR_NULL ) return(s); // return when find null
      s[i] = ch;
   }
   return(s);
}
int get_string(FILE *fspec, char *string)
{
#ifdef DEBUG
  int rvalue=fget_c_string(string, MAX_STR_LEN, fspec);
  printf("\n fget_c_string returns %s", string);
  return(rvalue);
#else
  return(fget_c_string(string, MAX_STR_LEN, fspec));
#endif
}
#define REWIND_STREAM 100
/* ************************************************************************** */
int fget_c_string(char *string, int Max_Str_Len, FILE *fspec)
{
   /* gets a string from the input and removes comments from it */
   /* allows comments in standard "c" syntax,
           starting with / *
      ending with  * /  */
   /* also allows c++ type comments, // causes rest of line to be skipped */

   int check;
   char comment_start[4]="/*";  /* signals start of comment */
   char comment_stop[4]="*/";   /* signals end of comment   */
   int clen; /* length of string for start/stop*/
   int ilen; /* length of input string */
   char *istring; /* input string */
   int olen; /* location on output string */
   int icnt; /* location on string */

   //   int n_pass = 0; /* Number of passes through the file looking for a value */

   olen = 0;
   /* allocate memory for input string */
   istring = (char *)calloc(Max_Str_Len,sizeof(char));
   if(istring == NULL)
   {
      printf("\n ERROR: Allocating memory for input string if fget_c_string");
      return(FAIL);
   }
   strnset(string,'\0',Max_Str_Len); /* null entire output string */
   strnset(istring,'\0',Max_Str_Len); /* null entire input string */

#ifdef DEBUG
   printf ("\n --------------fget_c_string");
#endif
   clen = strlen(comment_start);
   /* read in the line, verify that it exists */
   do{
      /* read in a line from the file */
      while(fgets(istring, Max_Str_Len, fspec) == NULL) /* output warning if not a valid read */
      {
#ifdef DEBUG
        printf("\n istring: %s", istring);
#endif
#ifdef ALLOW_REWIND
   if(n_pass) /* if already gone through file once looking for value, quit */
#endif
   {
#ifdef DEBUG
           //  printf ("\n***End of Input File in get_string, closing");
#endif
           //  printf ("\nERROR: Reading File : End of File On Read ");
           // fclose(fspec);
           free(istring);
           return(FAIL);
        }
#ifdef ALLOW_REWIND
        n_pass++;      /* increment the number of times through the file */
        rewind(fspec); /* rewind to the beginning of the file */
        free(istring);
        return(REWIND_STREAM);
#endif
      }
#ifdef DEBUG
        printf("\n istring: %s", istring);
#endif
      ilen = strlen(istring); /* length of input string */
      istring[ilen]='\0'; /* null terminate the string */
      if(ilen < clen) /* not possible to have comment on the line */
      {               /* so output the string as is */
         strcpy(string,istring);
         olen = strlen(string);
      }
      else
      {
        /* strip comments out of input string */
        icnt=0;
        do{
          check = 1;
          if(icnt < ilen - clen)  /* make sure have enough characters for start of comment */
             check = strncmp(istring+icnt,comment_start,clen); /* check if start of comment */
          if(check == 0) /* comment found for standard c syntax */
          {
            /* find end of comment */
            icnt+=clen; /* advance past comment delimeter */
            clen=strlen(comment_stop); /* get length of end of comment delimiter */
            /* look for end of comment till end of string */
            do{
               check = 1;
               if(icnt < ilen - clen)  /* make sure have enough characters for end of comment */
                  check = strncmp(istring+icnt, comment_stop,clen);
               if(check != 0)  /* if not end of comment */
               {
                  icnt++; /* increment location on string */
                  if(icnt>ilen) /* if advance past end of string, get a new one */
                  {
                     if(fgets(istring, Max_Str_Len, fspec) == NULL) /* output warning if not a valid read */
                     {
                        printf ("\nERROR: Reading File, looking for end of comment %s",comment_stop);
                        // fclose(fspec);
                        free(istring);
                        return(FAIL);
                     }
                     ilen = strlen(istring); /* get length of this new string */
                     /* null terminate the string */
                     istring[ilen]='\0';
                     icnt = 0; /* reset the counter to the start of the string */
                  }
               }
               else
               {
                  icnt+=clen; /* advance past comment delimiter */
               }
            }while(check != 0); /* end of comment found */
          }  /* end if */
          else /* check if comment is in c++ format */
          {
             check = strncmp(istring+icnt, "//",2);
             if(check == 0) /* c++ style comment found */
             {  /* skip till end of string */
                icnt = ilen;
                string[olen++]='\n';
                string[olen]='\0';
             }
             else /* is a valid character for the string */
             {
                string[olen++] = istring[icnt++]; /* append value to the string */
                string[olen]='\0';
             }
          }
        }while(icnt < ilen          &&    /* do till end of string */
               olen < Max_Str_Len); /* and output string not too long */
        /* check for only carriage return (should have been caught above) */
        if(olen == 1 && string[0] == '\n') olen = 0;

      }  /* end else */
   }while(olen == 0); /* do till read in a string */
   if(olen == Max_Str_Len)
   {
      printf ("\nERROR: Input line too long");
      // fclose(fspec);
      free(istring);
      return(FAIL);
   }
   free(istring);
   return(OK);
}

